package com.lzs.common.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lzs.common.annotations.Log;
import com.lzs.common.dao.SysLogsDao;
import com.lzs.common.pojo.common.SysLogs;
import com.lzs.common.thread.ThreadLocalUtil;
import com.lzs.common.utils.IPUtils;
import com.lzs.common.utils.MyHttpUtils;
import com.lzs.common.utils.SecurityUser;
import com.lzs.common.utils.SecurityUserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Aspect
@Component
@Slf4j
public class SystemLogAspect {

    @Autowired
    private SysLogsDao sysLogsDao;

    //Controller层切点
    @Pointcut("@annotation(com.lzs.common.annotations.Log)")
    public void controllerAspect() {
        log.info("================ controllerAspect ====================");
    }

    /**
     * 前置通知 用于拦截Controller层记录用户的操作
     *
     * @param joinPoint 切点
     */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {
        /*用isDebugEnabled方法判断下是能提升性能的*/
        if (log.isInfoEnabled()) {
            String userId = "";
            try {
                SecurityUser securityUser = SecurityUserUtils.getSecurityUser();
                userId = securityUser.getUserId();
            }catch (Exception e){

            }
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            Class clazz = joinPoint.getTarget().getClass();

            String targetName = clazz.getSimpleName();
            String methodName = joinPoint.getSignature().getName();
            Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
            Method method = null;
            try {
                method = clazz.getMethod(methodName,parameterTypes);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }

            Log logAnnotation = method.getAnnotation(Log.class);
            SysLogs sysLogs = new SysLogs();
            sysLogs.setOperationStatus("1");
            sysLogs.setOperationUserId(userId);
            String ipAddr = IPUtils.getIpAddr(request);
            sysLogs.setRequestIp(ipAddr);
            //描述
            String operationDescribe = logAnnotation.value();
            String describe = logAnnotation.operationType().getDescribe();
            sysLogs.setOperationDescribe(describe+"|"+operationDescribe);

            String requestParam = "";
            if (
                    request.getMethod().equals(HttpMethod.POST.toString())
                            || request.getMethod().equals(HttpMethod.PUT.toString())
            ) {
                //上传文件请求
                if (StringUtils.indexOf(request.getContentType(),"multipart/form-data")==0) {
                    log.info("上传文件请求，跳过参数打印");
                }else {
                    String postData = MyHttpUtils.getPostData(request);
                    requestParam = postData;
                    log.info("body参数=[{}]",postData);
                }

            }else {
                Map<String, String[]> parameterMap = request.getParameterMap();
//                log.info("路径参数=[{}]",JSON.toJSONString(parameterMap));
                requestParam = JSON.toJSONString(parameterMap);
            }
            if (requestParam.length()>500){
                requestParam = requestParam.substring(0, 500);
            }
            sysLogs.setRequestParams(requestParam);

            //请求路径
            StringBuffer requestURL = request.getRequestURL();
            sysLogs.setRequestUrl(requestURL.toString());
            String requestParams = "";
            if (joinPoint.getArgs() != null) {
                try {
                    requestParams = JSON.toJSONString(joinPoint.getArgs());
                }catch (Exception e){
                    log.error("异常:"+e.getMessage());
                }
            }
            if (Objects.nonNull(requestParams) && requestParams.length() >= 5001) {
                requestParams = requestParams.substring(0, 5000);
//                sysLogs.setRequestParams(requestParams);
            }
            sysLogs.setRequestParams(requestParams);
            sysLogs.setResponseData("");
            sysLogsDao.insert(sysLogs);
            ThreadLocalUtil.addLogId(sysLogs.getId());
            log.info("==================== before ====================" + joinPoint);
        }
    }
//    /**
//     * 后置通知 用于拦截Controller层记录用户的操作
//     *
//     * @param joinPoint 切点
//     */
//    @After("controllerAspect()")
//    public void after(JoinPoint joinPoint) {
//        log.info("==================== after ====================");
//        /* HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//          HttpSession session = request.getSession();  */
//        //读取session中的用户
//        // User user = (User) session.getAttribute("user");
//        //请求的IP
//        //String ip = request.getRemoteAddr();
////        User user = new User();
////        user.setUserId(1);
////        /*  System.out.println("userid会打印什么 : " + user.getUserId());*/
////        try {
////
////            String targetName = joinPoint.getTarget().getClass().getName();
////            String methodName = joinPoint.getSignature().getName();
////            Object[] arguments = joinPoint.getArgs();
////            Class targetClass = Class.forName(targetName);
////            Method[] methods = targetClass.getMethods();
////            String logType = "";
////            String logContent = "";
////            for (Method method : methods) {
////                if (method.getName().equals(methodName)) {
////                    Class[] clazzs = method.getParameterTypes();
////                    if (clazzs.length == arguments.length) {
////                        logType = method.getAnnotation(SystemControllerLog.class).actionType();
////                        logContent = method.getAnnotation(SystemControllerLog.class).descrption();
////                        break;
////                    }
////                }
////            }
////            //*========控制台输出=========*//
////            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
////            System.out.println("方法描述:" + logContent);
////            System.out.println("请求人:" + user.getUserName());
////            //*========数据库日志=========*//
////            Log log = new Log();
////            log.setUserId(1);
////            log.setLogType(logType);
////            log.setLogContent(logContent);
////            log.setLogErrorCode(HttpStatus.OK.toString());
////            log.setLogDate(new Date());
////            //保存数据库
////            ls.getInsertLog(log);
////        } catch (Exception e) {
////            //记录本地异常日志
////            log.error("异常信息:{}", e.getMessage());
////        }
//    }

    //配置后置返回通知,使用在方法aspect()上注册的切入点
    @AfterReturning(returning="rvt", value = "controllerAspect()")
    public void afterReturn(JoinPoint joinPoint,Object rvt) {
        if (log.isInfoEnabled()) {
            String logId = ThreadLocalUtil.getLogId();
            SysLogs sysLogs = new SysLogs();
            sysLogs.setId(logId);
            String resultJson = JSONObject.toJSONString(rvt);
            if(resultJson.length()>800){
                resultJson = resultJson.substring(0,800);
            }
            sysLogs.setResponseData(resultJson);
            sysLogs.setOperationStatus("0");
            sysLogsDao.updateById(sysLogs);
            log.info("==================== afterReturn ====================" + joinPoint);
        }
    }

    /**
     * 异常通知 用于拦截记录异常日志
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        String logId = ThreadLocalUtil.getLogId();
        SysLogs sysLogs = new SysLogs();
        sysLogs.setId(logId);
        String msg = e.getMessage();
        if (StringUtils.isBlank(msg)) {
            msg = "空指针异常";
        }
        if(msg.length()>500){
            msg = msg.substring(0,500);
        }
        sysLogs.setErrMsg(msg);
        sysLogs.setOperationStatus("1");
        sysLogsDao.updateById(sysLogs);
        /*==========记录本地异常日志==========*/
        log.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage());

    }

}
